// Fill out your copyright notice in the Description page of Project Settings.


#include "AbilitySystem/AbilityTasks/AbilityTask_TargetDataUnderMouse.h"

#include "AbilitySystemComponent.h"

UAbilityTask_TargetDataUnderMouse* UAbilityTask_TargetDataUnderMouse::TargetDataUnderMouse(
	UGameplayAbility* OwningAbility
)
{
	UAbilityTask_TargetDataUnderMouse* MyObj = NewAbilityTask<UAbilityTask_TargetDataUnderMouse>(OwningAbility);
	return MyObj;
}

void UAbilityTask_TargetDataUnderMouse::OnTargetDataReplicatedCallback(
	const FGameplayAbilityTargetDataHandle& TargetDataHandle, FGameplayTag GameplayTag
)
{
	// 通知客户端 服务器端已经接收并处理了从客户端复制的目标数据（将服务器的TargetData应用到客户端，并清除掉缓存）
	AbilitySystemComponent->ConsumeClientReplicatedTargetData(GetAbilitySpecHandle(),GetActivationPredictionKey());
	if (ShouldBroadcastAbilityTaskDelegates())
	{
		ValidData.Broadcast(TargetDataHandle);
	}
}

void UAbilityTask_TargetDataUnderMouse::Activate()
{
	// 如果是本地控制，实现将数据发射到服务器端
	bool bIsLocallyControlled = Ability->GetCurrentActorInfo()->IsLocallyControlled();
	if (bIsLocallyControlled)
	{
		SendMouseCursorData();

	}

	const FGameplayAbilitySpecHandle SpecHandle = GetAbilitySpecHandle();
	
	const FPredictionKey ActivationPredictionKey = GetActivationPredictionKey();
	
	// 目标数据设置委托,当目标数据改变时广播委托
	AbilitySystemComponent.Get()->AbilityTargetDataSetDelegate(SpecHandle, ActivationPredictionKey).AddUObject(
		this,
		&ThisClass::OnTargetDataReplicatedCallback
	);
	// 如果目标数据设置了,则广播TargetDataSet委托
	const bool bHasCalledDelegate = AbilitySystemComponent.Get()->CallReplicatedTargetDataDelegatesIfSet(
		SpecHandle,
		ActivationPredictionKey
	);
	if (!bHasCalledDelegate)
	{
		// 服务器端设置等待PlayerData数据的上传
		SetWaitingOnRemotePlayerData();
	}
}


void UAbilityTask_TargetDataUnderMouse::SendMouseCursorData()
{
	// 创建一个预测窗口,该窗口允许客户端在不确定服务器响应的情况下,对游戏状态进行预测更新.出域(出作用域)时结束预测
	FScopedPredictionWindow ScopedPrediction(AbilitySystemComponent.Get(), true);

	// 获取鼠标拾取结果
	APlayerController* PC = Ability->GetCurrentActorInfo()->PlayerController.Get();
	FHitResult CursorHit;
	PC->GetHitResultUnderCursor(ECC_Visibility, false, CursorHit);

	// 创建需要上传到服务器的TargetData
	FGameplayAbilityTargetData_SingleTargetHit* Data = new FGameplayAbilityTargetData_SingleTargetHit();
	Data->HitResult = CursorHit;

	// 创建TargetDataData句柄,上传到服务器需要上传句柄
	FGameplayAbilityTargetDataHandle DataHandle;
	DataHandle.Add(Data);

	
	if (!Ability->GetCurrentActorInfo()->IsNetAuthority())
	{
			// severRPC.将目标数据上传到服务器
        	AbilitySystemComponent->ServerSetReplicatedTargetData(
        		GetAbilitySpecHandle(),
        		GetActivationPredictionKey(),
        		DataHandle,
        		FGameplayTag(),
        		AbilitySystemComponent->ScopedPredictionKey
        	);
	}
	

	if (ShouldBroadcastAbilityTaskDelegates())
	{
		// 广播委托
		ValidData.Broadcast(DataHandle);
	}
}
